unit database_classes;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, PairSplitter, StdCtrls,
  Buttons, ExtCtrls, Menus, database_base, itemselectorframeunit, traitlist,
  learninglistframeunit, fpjson, BGRABitmapTypes, BGRABitmap,
  parametercurvesformunit, LCLTranslator;

type

  { TDatabaseClassesFrame }

  TDatabaseClassesFrame = class(TDatabaseBaseFrame)
    AdditionalDataPairSplitter: TPairSplitter;
    AdditionalDataPanel: TPanel;
    AgiSpeedButton: TSpeedButton;
    AtkSpeedButton: TSpeedButton;
    ChangeExpCurveButton: TButton;
    ClassLearningListFrame: TLearningListFrame;
    ClassTraitListFrame: TTraitListFrame;
    CopyMenuItem: TMenuItem;
    CopyMenuItem1: TMenuItem;
    CutMenuItem: TMenuItem;
    CutMenuItem1: TMenuItem;
    DataListBox: TListBox;
    DefSpeedButton: TSpeedButton;
    DeleteMenuItem: TMenuItem;
    DeleteMenuItem1: TMenuItem;
    EditMenuItem: TMenuItem;
    EditMenuItem1: TMenuItem;
    ClassSelectorFrame: TItemSelectorFrame;
    ExpCurveLabel: TLabel;
    ExpCurveValueLabel: TLabel;
    GeneralSettingsGroupBox: TGroupBox;
    ItemSelectorLabel: TLabel;
    ItemSelectorListBox: TListBox;
    ItemSelectorPanel: TPanel;
    LearnedSkillsGroupBox: TGroupBox;
    LearningsPairSplitterSide: TPairSplitterSide;
    LukSpeedButton: TSpeedButton;
    MainDataPanel: TPanel;
    MatSpeedButton: TSpeedButton;
    MdfSpeedButton: TSpeedButton;
    MmpSpeedButton: TSpeedButton;
    MphSpeedButton: TSpeedButton;
    NameEdit: TEdit;
    NameLabel: TLabel;
    NotesGroupBox: TGroupBox;
    NotesMemo: TMemo;
    NotesPairSplitterSide: TPairSplitterSide;
    ParamCurvesGroupBox: TGroupBox;
    ParamsLearningsPairSplitter: TPairSplitter;
    ParamsPairSplitterSide: TPairSplitterSide;
    PasteMenuItem: TMenuItem;
    PasteMenuItem1: TMenuItem;
    MainDataScrollBox: TScrollBox;
    SetMaximumButton: TButton;
    SelectorContentSplitter: TSplitter;
    MainAdditionalContentSplitter: TSplitter;
    TraitsGroupBox: TGroupBox;
    TraitsListBox: TListBox;
    TraitsPairSplitterSide: TPairSplitterSide;
    procedure ChangeExpCurveButtonClick(Sender: TObject);
    procedure Init; override;
    procedure ItemSelectorPanelClick(Sender: TObject);
    procedure LoadClassData(NewId: Integer);
    function GetSelectedClass: TJSONObject;
    function FormatExpCurve(ClassObj: TJSONObject): String;
    procedure NameEditChange(Sender: TObject);
    procedure NotesMemoChange(Sender: TObject);
    procedure ParamSpeedButtonClick(Sender: TObject);
    procedure UpdateParamCurveGlyphs;
    procedure UpdateParamCurveGlyph(Btn: TSpeedButton);
  private
    CurrentId: Integer;
    IsLoading: Boolean;
  public

  end;

resourcestring
  ClassesHeader = 'Classes';

implementation

uses
  Math, constants, expcurveformunit;

{$R *.lfm}

procedure TDatabaseClassesFrame.Init;
begin
  IsLoading := True;
  ClassSelectorFrame.SetData(Db.Classes, @Db.ResizeClasses, @LoadClassData);
  ClassSelectorFrame.Title := ClassesHeader;
  ClassSelectorFrame.JsonDataType := 'application/rpgmv-classes';
  ClassSelectorFrame.CreateElementCallback := @Db.CreateEmptyClass;

  ClassTraitListFrame.SetDatabase(Db);
  ClassLearningListFrame.SetDatabase(Db);


  LoadClassData(1);
end;

procedure TDatabaseClassesFrame.ItemSelectorPanelClick(Sender: TObject);
begin

end;

procedure TDatabaseClassesFrame.ChangeExpCurveButtonClick(Sender: TObject);
var
  ExpParamsExist: Boolean;
  BaseValue: Integer = 10;
  ExtraValue: Integer = 10;
  AccelA: Integer = 10;
  AccelB: Integer = 10;
  ClassObj: TJSONObject;
  ExpParams: TJSONArray;
begin
  ClassObj := GetSelectedClass;

  ExpParamsExist := ClassObj.Find('expParams', ExpParams);
  if ExpParamsExist then begin
    if ExpParams.Count >= 1 then
      BaseValue := ExpParams.Integers[0];
    if ExpParams.Count >= 2 then
      ExtraValue := ExpParams.Integers[1];
    if ExpParams.Count >= 3 then
      AccelA := ExpParams.Integers[2];
    if ExpParams.Count >= 4 then
      AccelB := ExpParams.Integers[3];
  end;

  if ExpCurveForm.ShowExpCurveSetup(BaseValue, ExtraValue, AccelA, AccelB) then begin
    if not ExpParamsExist then begin
      ExpParams := TJSONArray.Create([
        ExpCurveForm.BaseValue, ExpCurveForm.ExtraValue,
        ExpCurveForm.AccelA, ExpCurveForm.AccelB
      ]);
      ClassObj.Add('expParams', ExpParams)
    end else begin
      ExpParams.Integers[0] := ExpCurveForm.BaseValue;
      ExpParams.Integers[1] := ExpCurveForm.ExtraValue;
      ExpParams.Integers[2] := ExpCurveForm.AccelA;
      ExpParams.Integers[3] := ExpCurveForm.AccelB;
    end;
    ExpCurveValueLabel.Caption := FormatExpCurve(ClassObj);
  end;
end;

procedure TDatabaseClassesFrame.LoadClassData(NewId: Integer);
var
  ClassObj: TJSONObject;
  ClassObjName, Notes: String;
  ClassNameJson, NotesJson: TJSONString;
  TraitList, LearningList: TJSONArray;
begin
  IsLoading := True;

  CurrentId := NewId;
  ClassObj := GetSelectedClass;

  ClassObjName := '';
  if (ClassObj <> nil) and ClassObj.Find('name', ClassNameJson) then
    ClassObjName := ClassNameJson.AsString;
  NameEdit.Text := ClassObjName;

  ExpCurveValueLabel.Caption := FormatExpCurve(ClassObj);

  UpdateParamCurveGlyphs;

  Notes := '';
  if (ClassObj <> nil) and ClassObj.Find('note', NotesJson) then
    Notes := NotesJson.AsString;
  NotesMemo.Text := Notes;

  if ClassObj.Find('traits', TraitList) then
    ClassTraitListFrame.SetTraitList(TraitList)
  else
    ClassTraitListFrame.SetTraitList(nil);

  if ClassObj.Find('learnings', LearningList) then
    ClassLearningListFrame.SetEditedLearnings(LearningList)
  else
    ClassLearningListFrame.SetEditedLearnings(nil);

  IsLoading := False;
end;

function TDatabaseClassesFrame.GetSelectedClass: TJSONObject;
begin
  GetSelectedClass := Db.Classes.Objects[CurrentId];
end;

function TDatabaseClassesFrame.FormatExpCurve(ClassObj: TJSONObject): String;
var
  Formatted, Item: String;
  ExpParams: TJSONArray;
  I: Integer;
begin
  Formatted := '[missing data]';
  if (ClassObj <> nil) and ClassObj.Find('expParams', ExpParams) then begin
    Formatted := '[';
    for I := 0 to ExpParams.Count -1 do begin
      Item := '';
      if I > 0 then
        Item := ', ';

      Item := Item + IntToStr(ExpParams.Integers[I]);

      Formatted := Formatted + Item;
    end;
    Formatted := Formatted + ']';
  end;

  FormatExpCurve := Formatted;
end;

procedure TDatabaseClassesFrame.NameEditChange(Sender: TObject);
var
  ClassObj: TJSONObject;
begin
  if IsLoading then
    Exit;

  ClassObj := GetSelectedClass;
  if ClassObj <> nil then begin
    ClassObj.Strings['name'] := NameEdit.Text;
    ClassSelectorFrame.RefreshSelectedName;
  end;
end;

procedure TDatabaseClassesFrame.NotesMemoChange(Sender: TObject);
var
  ClassObj: TJSONObject;
begin
  if IsLoading then
    Exit;

  ClassObj := GetSelectedClass;
  if ClassObj <> nil then begin
     ClassObj.Strings['note'] := NotesMemo.Text;
  end;
end;

procedure TDatabaseClassesFrame.ParamSpeedButtonClick(Sender: TObject);
begin
  ParameterCurvesForm.EditParams(Db, GetSelectedClass, (Sender as TSpeedButton).Tag);
  UpdateParamCurveGlyphs;
end;

procedure TDatabaseClassesFrame.UpdateParamCurveGlyphs;
begin
  UpdateParamCurveGlyph(MphSpeedButton);
  UpdateParamCurveGlyph(MmpSpeedButton);
  UpdateParamCurveGlyph(AtkSpeedButton);
  UpdateParamCurveGlyph(DefSpeedButton);
  UpdateParamCurveGlyph(MatSpeedButton);
  UpdateParamCurveGlyph(MdfSpeedButton);
  UpdateParamCurveGlyph(AgiSpeedButton);
  UpdateParamCurveGlyph(LukSpeedButton);
end;

procedure TDatabaseClassesFrame.UpdateParamCurveGlyph(Btn: TSpeedButton);
var
  Graph: TBGRABitmap;
  ResizedGraph: TBGRACustomBitmap;
  ClassObj: TJSONObject;
  Params, ParamValues: TJSONArray;
  ParamId: Integer;
  ParamValue: Integer;
  I: Integer;
begin
  ParamId := Btn.Tag;
  Graph := TBGRABitmap.Create(99, 100, clWhite);

  ClassObj := GetSelectedClass;
  if (ClassObj <> nil) and ClassObj.Find('params', Params) then begin
    if (ParamId >= 0) and (ParamId < Params.Count) then begin
      ParamValues := Params.Arrays[ParamId];
      for I := 1 to Min(99, ParamValues.Count - 1) do begin
        ParamValue := ParamValues[I].AsInteger;
        with Graph.CanvasBGRA do begin
          Pen.Color := ColorToBGRA(ParameterColours[ParamId]);
          Pen.Width := 1;
          MoveTo(I, 100);
          if ParamId < 2 then
            LineTo(I, 99 - Min(99, ParamValue div 100))
          else
            LineTo(I, 99 - Min(99, ParamValue div 10));
        end;
      end;
    end;
  end;

  ResizedGraph := Graph.Resample(48, 48);

  Btn.Glyph.Assign(ResizedGraph);

  ResizedGraph.Free;
  Graph.Free
end;

end.

